/*
 * aggregate_stats macros and globals
 *
 * Copyright (c) 2006 Nikolai Joukov and Erez Zadok
 * Copyright (c) 2006 Stony Brook University
 */

#ifndef _AGGREGATE_STATS_H_
#define _AGGREGATE_STATS_H_

#include <sys/shm.h>

int* aggregate_stats;

#ifndef AGGREGATE_STATS_RESOLUTION
#define AGGREGATE_STATS_RESOLUTION 1
#endif

#ifdef __ia64__
#define RDTSC(qp) \
	do { \
		unsigned long result; \
		__asm__ __volatile__("mov %0=ar.itc" : "=r" (result) :: "memory"); \
		qp = result; \
	} while (0);
#else
#define RDTSC(qp) \
	do { \
		unsigned long lowPart, highPart; \
		__asm__ __volatile__("rdtsc" : "=a" (lowPart), "=d" (highPart)); \
		qp = (((unsigned long long) highPart) << 32) | lowPart; \
	} while (0);
#endif

#define AGGREGATE_STATS_PRE \
	long long l_aggregate_stats; \
	RDTSC(l_aggregate_stats);

#define AGGREGATE_STATS_POST(op) \
	do { \
		long long ll; \
		int bucket, delay; \
		RDTSC(ll); \
		delay = (int)((ll - l_aggregate_stats) >> 5); \
		for (bucket = 0; delay >> AGGREGATE_STATS_RESOLUTION; bucket += AGGREGATE_STATS_RESOLUTION) \
			delay >>= 1; \
		if (AGGREGATE_STATS_RESOLUTION == 2) \
			bucket += 2 + (delay & 1); \
		aggregate_stats[(op) * AGGREGATE_STATS_RESOLUTION * 32 + bucket]++; \
	} while(0);

#if AGGREGATE_STATS_OP_MAX == 1
#define AGGREGATE_STATS_OP_NAMES ""
#else
#define AGGREGATE_STATS_OP_NAMES aggregate_stats_op_names[i]
#endif

#define AGGREGATE_STATS_PRINT \
	do { \
		int i, ii; \
		for (i = 0; i < AGGREGATE_STATS_OP_MAX; i++) { \
			printf("OP_%s ? ? ", AGGREGATE_STATS_OP_NAMES); \
			for (ii = 0; ii < 32 * AGGREGATE_STATS_RESOLUTION; ii++) \
				printf("%d ", aggregate_stats[i * AGGREGATE_STATS_RESOLUTION * 32 + ii]); \
			printf ("\n"); \
		} \
	} while(0);

#define AGGREGATE_STATS_EXIT AGGREGATE_STATS_PRINT \
	shmdt(aggregate_stats);

#define AGGREGATE_STATS_INIT \
	do { \
		int shmid; \
		if ((shmid = shmget(4444, 1, IPC_CREAT | 0666)) < 0) { \
			perror("shmget"); \
			exit(1); \
		} \
		aggregate_stats = (int*)shmat(shmid, NULL, 0); \
		if (aggregate_stats == (void*)-1) { \
			perror("shmat"); \
			exit(1); \
		} \
		memset(aggregate_stats, 0, AGGREGATE_STATS_RESOLUTION * \
			32 * sizeof(int) * AGGREGATE_STATS_OP_MAX); \
	} while (0);

#define AGGREGATE_STATS_DO(what, op) \
	do { \
		AGGREGATE_STATS_PRE; \
		what; \
		AGGREGATE_STATS_POST((op)); \
	} while (0);

#endif

